package com.meng.thrift.client.thrift.util;

import com.meng.thrift.client.common.LoggerUtil;
import org.apache.thrift.async.TAsyncClientManager;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.protocol.TProtocolFactory;
import org.apache.thrift.transport.*;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;


/**
 *
 * 获取服务端对象 返回给客户端
 *
 * @author MENG
 * @version 2017/11/17
 * @see
 */
public class ThriftClientFactory
{

    private static final int SYNC_TIMEOUT = 5000;

    private static final int ASYNC_TIMEOUT = 10000;

    public static Object createThriftObject(Class<?> clazz, ThriftIpPortEnum thriftEnum,
                                            String clientName)
    {
        if(clientName.equals("Client"))
        {
            //sync client    调用方法需要等待服务端方法执行完毕 拿到返回值 再继续执行后面代码

            return getSyncClient(clazz,thriftEnum);

        }
        else if(clientName.equals("AsyncClient"))
        {
            //async client   调用方法不需要等待服务端执行完毕, 直接执行后面代码，服务端执行完毕后会进入回调类的onComplete()方法

            return getAsyncClient(clazz,thriftEnum);
        }

        return null;
    }

    /**
     *
     * SyncClient
     *
     * @return SyncClient
     */
    public static Object getSyncClient(Class<?> interfaceClientClazz,ThriftIpPortEnum thriftIpPortEnum)
    {
        TTransport transport = null;

        Object object = null;

        Constructor constructor = null;

        // 协议要和服务端一致   TProtocol 与服务端一至
        transport = new TFramedTransport(new TSocket(thriftIpPortEnum.getIp(), thriftIpPortEnum.getPort(), SYNC_TIMEOUT));

        //二进制格式 数据传输协议
        TProtocol protocol = new TBinaryProtocol(transport);

        try
        {
            constructor = interfaceClientClazz.getConstructor(TProtocol.class);
        }
        catch (NoSuchMethodException e)
        {
            LoggerUtil.logger.error("{}找不到对应的构造方法",interfaceClientClazz,e);
        }

        try
        {
            object = constructor.newInstance(protocol);
        }
        catch (InstantiationException e)
        {
            LoggerUtil.logger.error("Thrift Server端 对象创建失败",e);
        }
        catch (IllegalAccessException e)
        {
            LoggerUtil.logger.error("Thrift Server端 对象创建失败",e);
        }
        catch (InvocationTargetException e)
        {
            LoggerUtil.logger.error("Thrift Server端 对象创建失败",e);
        }

        try
        {
            transport.open();
        }
        catch (TTransportException e)
        {
            LoggerUtil.logger.error("Thrift 连接服务端失败 IP:{} PORT:{}",thriftIpPortEnum.getIp(),thriftIpPortEnum.getPort(),e);
        }

        return object;
    }

    /**
     *
     * AsyncClient
     *
     * @return AsyncClient
     */
    public static Object getAsyncClient(Class<?> interfaceClientClazz,
                                        ThriftIpPortEnum thriftIpPortEnum)
    {
        //传输层 这种transport是用于异步客户端
        TNonblockingTransport transport = null;

        Object object = null; //接收服务端对象

        Constructor constructor = null; //构造

        TAsyncClientManager clientManager = null; //不知道
        try
        {
            clientManager = new TAsyncClientManager();
        }
        catch (IOException e)
        {
            LoggerUtil.logger.error("Thrift 连接服务端失败 IP:{} PORT:{}",thriftIpPortEnum.getIp(),thriftIpPortEnum.getPort(),e);
        }

        try
        {
            //传输层 这种transport是用于异步客户端
            transport = new TNonblockingSocket(thriftIpPortEnum.getIp(), thriftIpPortEnum.getPort(), ASYNC_TIMEOUT);
        }
        catch (IOException e)
        {
            LoggerUtil.logger.error("Thrift 连接服务端失败 IP:{} PORT:{}",thriftIpPortEnum.getIp(),thriftIpPortEnum.getPort(),e);
        }

        //数据协议 与服务端一致
        TProtocolFactory tprotocol = new TBinaryProtocol.Factory();

        try
        {
            constructor = interfaceClientClazz.getConstructor(TProtocolFactory.class,TAsyncClientManager.class,TNonblockingTransport.class);
        }
        catch (NoSuchMethodException e)
        {
            LoggerUtil.logger.error("{}找不到对应的构造方法",interfaceClientClazz,e);
        }

        try
        {
            object = constructor.newInstance(tprotocol,clientManager,transport);
        }
        catch (InstantiationException e)
        {
            LoggerUtil.logger.error("Thrift Server端 对象创建失败",e);
        }
        catch (IllegalAccessException e)
        {
            LoggerUtil.logger.error("Thrift Server端 对象创建失败",e);
        }
        catch (InvocationTargetException e)
        {
            LoggerUtil.logger.error("Thrift Server端 对象创建失败",e);
        }

        return object;

    }

}
